package com.csw.android.androidtest.module.net.socket;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;

import com.csw.android.androidtest.R;
import com.csw.android.androidtest.net.socket.base.BaseSocket;
import com.csw.android.androidtest.net.socket.base.SocketListener;
import com.csw.android.androidtest.net.socket.udp.UDPSocket;
import com.csw.android.androidtest.view.TouchView;
import com.csw.android.dev_utils.ui.BaseFragment;
import com.csw.android.dev_utils.utils.GSONUtils;
import com.csw.android.dev_utils.utils.LogUtils;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

/**
 * udp 通常用于游戏数据，即时画面传输，其稳定性上不是很可靠，会出现丢包现象
 * <p>
 * 对于这些应用场景来说，我们只关心最新的一帧画面的数据，对于其之前的数据并没有什么关联性，中间某些包丢失也没关系。
 * 一般来说一包数据控制在1472byte，由于可能出现丢包，所以一次数据分很多包的话就要注意了，分越多，其中某一包丢失会
 * 导致此次的数据都损坏不可用，在网络传输上，由于不同包可能走了不同路由器，最终到达顺序可能与发送数据不同，这个也
 * 要注意怎么去收集一次数据然后对包进行排序。
 * <p>
 * 以下展示一个本地127.0.0.1通过端口udp socket通信，实现上下两个view的触摸位置同步
 * <p>
 * 通常来讲，通信都分客户端和服务端，服务端可以通过监听端口，接收到来自远端的信息时，对远端地址端口发送udp包来
 * 提供数据。udp在sdk上没有分服务端客户端的概念，udp的设计就是给某个ip地址的某个端口丢数据，他能否接收到与我无
 * 关，可以对接收到的包解析命令，并对包发送方反馈数据，可以接收多端信息，并对多端做出回应
 */
public class UDPSocketTest extends BaseFragment {
    private TouchView topTouchView;
    private TouchView bottomTouchView;
    private BaseSocket topSocket;
    private BaseSocket bottomSocket;


    @Override
    public int getContentViewID() {
        return R.layout.fragment_udp_socket_test;
    }

    @Override
    public void initView(@NotNull View rootView, @Nullable Bundle savedInstanceState) {
        super.initView(rootView, savedInstanceState);
        topTouchView = rootView.findViewById(R.id.topTouchView);
        topTouchView.setPointColor(Color.YELLOW);
        bottomTouchView = rootView.findViewById(R.id.bottomTouchView);
        bottomTouchView.setPointColor(Color.BLUE);
    }

    @Override
    public void initListener() {
        super.initListener();
        topTouchView.setOnPointInfoUpdateListener(new TouchView.OnPointInfoUpdateListener() {
            @Override
            public void onPointInfoUpdate(TouchView.PointInfo pointInfo) {
                topSocket.write(GSONUtils.INSTANCE.toJSONString(pointInfo).getBytes());
            }

            @Override
            public void onClearPointInfos() {
                topSocket.write("clear".getBytes());
            }
        });

        bottomTouchView.setOnPointInfoUpdateListener(new TouchView.OnPointInfoUpdateListener() {
            @Override
            public void onPointInfoUpdate(TouchView.PointInfo pointInfo) {
                bottomSocket.write(GSONUtils.INSTANCE.toJSONString(pointInfo).getBytes());
            }

            @Override
            public void onClearPointInfos() {
                bottomSocket.write("clear".getBytes());
            }
        });
    }

    @Override
    public void initData() {
        super.initData();
        //启动第一个udpSocket，指定本机ip，系统分配可用的端口
        topSocket = new UDPSocket("127.0.0.1", 0, new SocketListener() {
            @Override
            public void onPrepared(String ip, int port) {
                //端口分配完成，启动客户端（另一个udpSocket），往这个端口发送数据
                startClient();
            }

            @Override
            public void onError(Exception e) {
                LogUtils.INSTANCE.d(UDPSocketTest.this, "topSocket error");
            }

            @Override
            public void onClose() {

            }

            @Override
            public void onReceiveMessage(byte[] data) {
                String dataStr = new String(data);
                if ("clear".equalsIgnoreCase(dataStr)) {
                    topTouchView.clearPoint();
                } else {
                    TouchView.PointInfo p = GSONUtils.INSTANCE.parseObject(dataStr, TouchView.PointInfo.class);
                    if (p != null) {
                        topTouchView.setPointInfo(p);
                    }
                }
            }
        });
        topSocket.prepare();
    }

    private void startClient() {
        bottomSocket = new UDPSocket("127.0.0.1", 0, new SocketListener() {
            @Override
            public void onPrepared(String ip, int port) {
                //两个udpSocket都创建完成，设置各自的目标通信地址，
                bottomSocket.setDestInfo(topSocket.getIp(), topSocket.getPort());
                topSocket.setDestInfo(bottomSocket.getIp(), port);
                //开始接收目标地址数据
                topSocket.startRead();
                bottomSocket.startRead();
            }

            @Override
            public void onError(Exception e) {
                LogUtils.INSTANCE.d(UDPSocketTest.this, "bottomSocket error");
            }

            @Override
            public void onClose() {

            }

            @Override
            public void onReceiveMessage(byte[] data) {
                String dataStr = new String(data);
                if ("clear".equalsIgnoreCase(dataStr)) {
                    bottomTouchView.clearPoint();
                } else {
                    TouchView.PointInfo p = GSONUtils.INSTANCE.parseObject(dataStr, TouchView.PointInfo.class);
                    if (p != null) {
                        bottomTouchView.setPointInfo(p);
                    }
                }
            }
        });
        bottomSocket.prepare();
    }

    @Override
    public void onDestroyView() {
        topSocket.close();
        bottomSocket.close();
        topTouchView = null;
        bottomTouchView = null;
        super.onDestroyView();
    }
}
